<?php

namespace form;

/**
 * 表单生成类
 * Class FormHelper
 * @package org
 */
class FormHelper {

    /**
     * 生成文本框(按类型)
     * @param  string $type
     * @param  string $name
     * @param  string $value
     * @param  array $options
     * @return string
     */
    public function _input($type, $name, $value = null, $options = []) {
        if (!isset($options['name'])) $options['name'] = $name;
        $options['class'] = isset($options['class']) ? $options['class'] . (stripos($options['class'], 'form-control') !== false ? '' : ' form-control') : 'form-control';
        if (!in_array($type, ['password', 'checkbox', 'radio'])) {
            $options['value'] = $value;
        }
        $options['type'] = $type;
        return '<input' . $this->attributes($options) . ' />';
    }

    /**
     * 生成普通文本框
     * @param  string $name
     * @param  string $value
     * @param  array $options
     * @return string
     */
    public function _text($name, $value = null, $options = []) {
        return $this->_input('text', $name, $value, $options);
    }

    /**
     * 生成密码文本框
     * @param  string $name
     * @param  string $value
     * @param  array $options
     * @return string
     */
    public function _password($name, $value = null, $options = []) {
        return $this->_input('password', $name, '', $options);
    }

    /**
     * 生成隐藏文本框
     * @param  string $name
     * @param  string $value
     * @param  array $options
     * @return string
     */
    public function _hidden($name, $value = null, $options = []) {
        return $this->_input('hidden', $name, $value, $options);
    }

    /**
     * 生成switch组件
     * @param $name
     * @param $value
     * @param array $options data-option='{"onText":"开启文字","offText":"关闭文字","onColor":"success","offColor":"danger","size":"lg","callfn":"switchCallfn"}'
     * @return string
     */
    public function _switch($name, $value, $options = []) {
        $options['class'] = isset($options['class']) ? $options['class'] . ' f-switch' : 'f-switch';
        return $this->_input('checkbox', $name, $value, $options);
    }

    /**
     * 生成tags组件
     * @param $name
     * @param $value
     * @param array $options
     * @return string
     */
    public function _tags($name, $value, $options = []) {
        if (!isset($options['id'])) $options['id'] = $name;
        $options['class'] = isset($options['class']) ? $options['class'] . ' f-tags' : 'f-tags';
        $options['data-value'] = $value;
        return $this->_input('text', $name, $value, $options);
    }

    /**
     * 生成颜色选择框
     * @param $name
     * @param $value
     * @param array $options
     * @return string
     */
    public function _color($name, $value, $options = []) {
        if (!isset($options['readonly'])) $options['readonly'] = 'readonly';
        $options['class'] = isset($options['class']) ? $options['class'] . ' f-colorpicker' : 'f-colorpicker';
        return $this->_input('text', $name, $value, $options);
    }

    /**
     * 生成多行文本框
     * @param  string $name
     * @param  string $value
     * @param  array $options
     * @return string
     */
    public function _textarea($name, $value = null, $options = []) {
        if (!isset($options['name'])) $options['name'] = $name;
        if (!isset($options['rows'])) $options['rows'] = 3;
        $value = html_out($value);
        $options['class'] = isset($options['class']) ? $options['class'] . (stripos($options['class'], 'form-control') !== false ? '' : ' form-control') : 'form-control';
        $options = $this->attributes($options);
        return '<textarea' . $options . '>' . $value . '</textarea>';
    }

    /**
     * 生成富文本编辑器
     * @param string $name
     * @param string $value
     * @param array $options
     * @return string
     */
    public function _ckeditor($name, $value = null, $options = []) {
        $options['class'] = isset($options['class']) ? $options['class'] . ' f-ckeditor' : 'f-ckeditor';
        return $this->_textarea($name, $value, $options);
    }

    /**
     * 生成下拉列表框
     * @param  string $name
     * @param  array $list
     * @param  mixed $selected
     * @param  array $options key name
     * @return string
     */
    public function _select($name, $selected = null, $options = []) {
        if(!isset($options['list-data'])){
            return '数据源不能为空！';
        }
        if (!isset($options['name'])) $options['name'] = $name;
        $options['class'] = isset($options['class']) ? $options['class'] . (stripos($options['class'], 'form-control') !== false ? '' : ' form-control') : 'form-control';
        $itemsKey = isset($options['items-key']) ? $options['items-key'] : 'id'; //不指定默认id
        $itemsName = isset($options['items-name']) ? $options['items-name'] : 'name'; //不指定默认name
        $emptyOption = $options['empty-option'];
        $html = [];
        if (isset($options['empty-option'])) {
            $empatyOption = explode('|', $emptyOption);
            $html[] = '<option value="' . $empatyOption[0] . '">' . $empatyOption[1] . '</option>';
        }
        $list = $this->getListData($options['list-data']);
        if(!empty($list)){
            foreach ($list as $k => $v) {
                $selectedHtml = ($v[$itemsKey] == $selected) ? 'selected' : '';
                $disabledHtml = isset($v['disabled']) ? $v['disabled'] : '';
                $html[] = '<option value="' . $v[$itemsKey] . '" ' . $selectedHtml . ' '.$disabledHtml.'>' . $v[$itemsName] . '</option>';
            }
        }
        $options = $this->attributes($options);
        $list = implode(PHP_EOL, $html);
        return "<select {$options}>{$list}</select>";
    }

    /**
     * 生成selectPage控件
     * 自定义多个搜索字段data-search(字段,隔开)
     * 自定义额外搜索条件data-query 字符串形式
     * @param $name 表单名称
     * @param $value 表单值
     * @param array $options 格式化回调formatItemFun，选择回调selectFun
     * @return string
     */
    public function _selectpage($name, $value, $options = []) {
        if(empty($options['data-url']) || empty($options['data-show']) || empty($options['data-key'])){
            return '参数配置错误！';
        }
        if(strstr($options['data-url'],'type=tree')!==false){
            $options['data-option']['pagination'] = false;
        }
        $options['class'] = isset($options['class']) ? $options['class'] . ' f-selectpage' : 'f-selectpage';
        return $this->_text($name, $value, $options);
    }

    /**
     * 生成selectPages控件 多选
     * @param $name 表单名称
     * @param $value 表单值
     * @param array $options 格式化回调formatItemFun，选择回调selectFun
     * @return string
     */
    public function _selectpages($name, $value, $options = []) {
        $options['data-option']['multiple'] = true;
        //$options['data-option']['selectToCloseList'] = true;
        return $this->_selectpage($name, $value,$options);
    }

    /**
     * 日期选择器
     * @param string $name
     * @param mixed $value
     * @param array $options
     * @return string
     */
    public function _laydate($name, $value, $options = []) {
        if (!isset($options['data-option'])) $options['data-option']['type'] = "date";
        $options['class'] = isset($options['class']) ? $options['class'] . ' f-laydate' : 'f-laydate';
        return $this->_input('text', $name, $value, $options);
    }

    /**
     * 项目列表控件
     * @param $name
     * @param $value
     * @return string
     */
    public function _input_array($name, $value, $options = []) {
        if(isset($options['datatype'])) unset($options['datatype']);
        $options = $this->attributes($options);
        $dataRow=[];
        if (!empty($value)) {
            foreach($value as $k=>$v){
                $dataRow[]=<<<EOT
<tr class="data-row-tpl">
    <td><input type="text" class="form-control item-input" data-name="key" name="items[{$k}][key]" value="{$v['key']}" placeholder="请输入键"></td>
    <td><input type="text" class="form-control item-input" data-name="value" name="items[{$k}][value]" value="{$v['value']}" placeholder="请输入值"></td>
    <td><input type="text" class="form-control item-input" data-name="remark" name="items[{$k}][remark]" value="{$v['remark']}" placeholder="请输入描述"></td>
    <td><a href="javascript:;" class="btn btn-danger btn-del"><i class="fa fa-times"></i></a></td>
</tr>
EOT;
            }
            $dataRowHtml = implode(PHP_EOL,$dataRow);
        }
        $html = <<<EOT
<table class="table f-input-array" data-name="{$name}" {$options}>
    <thead>
    <tr>
        <th width="180">键</th>
        <th width="180">值</th>
        <th>描述</th>
        <th width="100">操作</th>
    </tr>
    </thead>
    <tr class="data-row-tpl">
        <td><input type="text" class="form-control item-input" data-name="key" value="" placeholder="请输入键"></td>
        <td><input type="text" class="form-control item-input" data-name="value" value="" placeholder="请输入值"></td>
        <td><input type="text" class="form-control item-input" data-name="remark" value="" placeholder="请输入描述"></td>
        <td><a href="javascript:;" class="btn btn-info btn-add"><i class="fa fa-plus"></i></a></td>
    </tr>
    <tbody class="data-row">
{$dataRowHtml}
    </tbody>
</table>
EOT;
        return $html;
    }

    /**
     * 生成复选框
     * @param string $name
     * @param mixed $checked
     * @param array $options
     * @return string
     */
    public function _checkbox($name, $checked, $options = []) {
        if(!isset($options['list-data'])){
            return '数据源不能为空！';
        }
        $options['class'] = isset($options['class']) ? $options['class'] . (stripos($options['class'], 'f-icheck') !== false ? '' : ' f-icheck') : 'f-icheck';
        $itemsKey = isset($options['items-key']) ? $options['items-key'] : 'id'; //不指定默认id
        $itemsName = isset($options['items-name']) ? $options['items-name'] : 'name'; //不指定默认name
        $html = [];
        $list = $this->getListData($options['list-data']);
        if(!empty($list)){
            $options = $this->attributes($options);
            foreach ($list as $k => $v) {
                $checkedHtml = in_array($v[$itemsKey], explode(',', $checked)) ? 'checked' : '';
                $html[] = '<label class="icheck"><input type="checkbox" ' . $options . ' name="' . $name . '[]" value="' . $v[$itemsKey] . '" ' . $checkedHtml . ' /> ' . $v[$itemsName] . '</label>';
            }
        }
        return implode(PHP_EOL, $html);
    }

    /**
     * 生成单选框
     * @param string $name
     * @param mixed $checked
     * @param array $options
     * @return string
     */
    public function _radio($name, $checked, $options = []) {
        if(!isset($options['list-data'])){
            return '数据源不能为空！';
        }
        $options['class'] = isset($options['class']) ? $options['class'] . (stripos($options['class'], 'f-icheck') !== false ? '' : ' f-icheck') : 'f-icheck';
        $itemsKey = isset($options['items-key']) ? $options['items-key'] : 'id';
        $itemsName = isset($options['items-name']) ? $options['items-name'] : 'name';
        $html = [];
        $list = $this->getListData($options['list-data']);
        if(!empty($list)){
            $options = $this->attributes($options);
            foreach ($list as $k => $v) {
                $checkedHtml = $v[$itemsKey] == $checked ? 'checked' : '';
                $html[] = '<label class="icheck"><input type="radio" ' . $options . ' name="' . $name . '" value="' . $v[$itemsKey] . '" ' . $checkedHtml . ' /> ' . $v[$itemsName] . '</label>';
            }
        }
        return implode(PHP_EOL, $html);
    }

    /**
     * 上传图片(单图)
     * @param $name
     * @param $value
     * @param array $options //该处option对应上传按钮
     * @return string
     */
    public function _image($name, $value, $options = []) {
        if (!isset($options['name'])) $options['name'] = $name;
        if(isset($options['datatype'])) unset($options['datatype']);
        $idName = str_replace(["[","]"],'',$name);
        $options = $this->attributes($options);
        $html = <<<EOL
<div class="input-group">
    <input type="text" class="form-control" id="input-{$idName}" name="{$name}" value="{$value}" />
    <span class="input-group-addon f-uploadimg" id="{$idName}" {$options}><i class="fa fa-upload"></i> 上传</span>
    <span class="input-group-addon" onclick="utils.imgPreview($('#input-{$idName}').val())"><i class="fa fa-picture-o"></i> 预览</span>
</div>
EOL;
        return $html;
    }

    /**
     * 上传附件(单附件)
     * @param $name
     * @param $value
     * @param array $options
     * @return string
     */
    public function _file($name, $value, $options = []) {
        if (!isset($options['name'])) $options['name'] = $name;
        if(isset($options['datatype'])) unset($options['datatype']);
        $options = $this->attributes($options);
        $html = <<<EOL
<div class="input-group">
    <input type="text" class="form-control" id="input-{$name}" name="{$name}" value="{$value}" />
    <span class="input-group-addon f-uploadfile" id="{$name}" {$options}><i class="fa fa-upload"></i> 上传</span>
    <span class="input-group-addon" onclick="utils.filePreview($('#input-{$name}').val())"><i class="fa fa-eye"></i> 查看</span>
</div>
EOL;
        return $html;
    }

    /**
     * 生成多图上传组件
     * @param $name
     * @param $value
     * @param array $options
     * @return string
     */
    public function _images($name, $value, $options = []) {
        $imagesItem = '';
        if (!empty($value)) {
            foreach($value as $pic){
                $imagesItem[]=<<<EOT
<li class="item-row">
    <input type="hidden" name="{$name}[]" value="{$pic}" />
    <div class="img-box" style="background-image:url('{$pic}')">
        <a href="javascript:;" onclick="utils.upMove(this);"><i class="fa fa-arrow-left"></i></a>
        <a href="javascript:;" onclick="utils.downMove(this);"><i class="fa fa-arrow-right"></i></a>
        <a href="javascript:;" onclick="utils.delRow(this);"><i class="fa fa-trash-o"></i></a>
    </div>
</li>
EOT;
            }
            $imagesItemHtml = implode(PHP_EOL,$imagesItem);
        }
        if(isset($options['datatype'])) unset($options['datatype']);
        $options = $this->attributes($options);
        $html = <<<EOT
<div class="f-upload-images-box" data-upload="upload-{$name}" data-name="{$name}" {$options}>
    <ul class="f-upload-images-item">
{$imagesItemHtml}  
    </ul>
    <a class="img-upload-box" id="upload-{$name}"></a>
    <div class="clearfix"></div>
</div>
EOT;
        return $html;
    }

    /**
     * 生成多图带描述上传组件
     * @param $name
     * @param $value
     * @param array $options
     * @return string
     */
    public function _images_desc($name, $value, $options = []) {
        $imagesItem = '';
        if (!empty($value)) {
            foreach($value as $vo){
                $imagesItem[]=<<<EOT
<div class="col-lg-6 col-md-12 col-sm-12 item-row">
    <div class="img-box"  style="background-image:url('{$vo['url']}')">
        <a href="javascript:;" onclick="utils.upMove(this);"><i class="fa fa-arrow-left"></i></a>
        <a href="javascript:;" onclick="utils.downMove(this);"><i class="fa fa-arrow-right"></i></a>
        <a href="javascript:;" onclick="utils.delRow(this);"><i class="fa fa-trash-o"></i></a>
    </div>
    <div class="form">
        <div class="form-group">
            <input type="hidden" class="form-control" name="{$name}[url][]" value="{$vo['url']}">
            <input type="text" class="form-control" name="{$name}[title][]" value="{$vo['title']}" placeholder="请输入图片标题">
        </div>
        <div class="form-group">
            <textarea class="form-control" rows="2" name="{$name}[remark][]" placeholder="请输入图片摘要">{$vo['remark']}</textarea>
        </div>
        <div class="input-group link-input">
            <span class="input-group-addon"><i class="fa fa-link"></i></span>
            <input type="text" class="form-control" name="{$name}[href][]" value="{$vo['href']}">
        </div>
    </div>
</div>
EOT;
            }
            $imagesItemHtml = implode(PHP_EOL,$imagesItem);
        }
        if(isset($options['datatype'])) unset($options['datatype']);
        $options = $this->attributes($options);
        $html = <<<EOL
<div class="f-upload-images-remark-box" data-upload="{$name}" data-name="{$name}" {$options}>
    <a class="btn btn-info" id="{$name}" style="margin-bottom:10px;">上传图片</a>
    <div class="clearfix"></div>
    <div class="row f-upload-images-item">
{$imagesItemHtml}
    </div>
    <div class="clearfix"></div>
</div>
EOL;
        return $html;
    }

    /**
     * 上传多附件
     * @param $name
     * @param $value
     * @param array $options
     * @return string
     */
    public function _files($name, $value, $options = []) {
        $filesItem = '';
        if (!empty($value)) {
            foreach($value as $file){
                $filesItem[]=<<<EOT
<div class="item-row">
    <input type="hidden" name="{$name}[]" value="{$file}" />
    <a href="{\$file}" target="_blank" class="file-name">{\$file}</a>
    <div class="action-box">
         <a href="javascript:;" onclick="utils.upMove(this);"><i class="fa fa-arrow-up"></i></a>
         <a href="javascript:;" onclick="utils.downMove(this);"><i class="fa fa-arrow-down"></i></a>
         <a href="javascript:;" onclick="utils.delRow(this);"><i class="fa fa-trash-o"></i></a>
    </div>
</div>
EOT;
            }
            $filesItemHtml = implode(PHP_EOL,$filesItem);
        }
        if(isset($options['datatype'])) unset($options['datatype']);
        $options = $this->attributes($options);
        $html = <<<EOT
<div class="f-upload-file-box" data-upload="upload-{$name}" data-name="{$name}" $options>
    <a class="btn btn-info" id="upload-{$name}" style="margin-bottom:10px;">上传附件</a>
    <div class="clearfix"></div>
    <div class="f-upload-file-item">
{$filesItemHtml}
    </div>
    <div class="clearfix"></div>
</div>
EOT;
        return $html;
    }

    /**
     * 生成按钮
     * @param  string $value
     * @param  array $options
     * @return string
     */
    public function _button($value = null, $options = []) {
        if (!array_key_exists('type', $options)) {
            $options['type'] = 'button';
        }
        return '<button' . $this->attributes($options) . '>' . $value . '</button>';
    }

    /*
     * 数组转换字符串。
     *
     * @param  array $options
     * @return string
     */
    public function attributes($options) {
        $html = [];
        // 假设我们的keys 和 value 是相同的,
        // 拿HTML“required”属性来说,假设是['required']数组,
        // 会已 required="required" 拼接起来,而不是用数字keys去拼接
        foreach ((array)$options as $key => $value) {
            if(is_numeric($key)) $key = $value;
            $element = $this->attributeElement($key, $value);
            if (!is_null($element))
                $html[] = $element;
        }
        return count($html) > 0 ? ' ' . implode(' ', $html) : '';
    }

    /**
     * 拼接属性。
     *
     * @param  string $key     * @param  string $value
     * @return string
     */
    protected function attributeElement($key, $value) {
        if (in_array($key, ['empty-option', 'items-key', 'items-name','list-data','upload'])) return null;
        if (!is_null($value)) {
            if (is_array($value) || stripos($value, '"') !== false) {
                $value = is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value;
                return $key . "='" . $value . "'";
            } else {
                return $key . '="' . $value . '"';
            }
        }
    }

    /**
     * 解析传入数据
     * @param $listData
     * @return array|mixed
     */
    public function getListData($listData){
        if(is_object($listData)) $listData = $listData->isEmpty() ? [] : $listData->toArray(); //处理对象转数组
        if(!is_array($listData)){
            $listData = explode(":",$listData);
            $list=[];
            switch ($listData[0]){
                case 'url': //调用url回调
                    $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
                    $data = send_http($protocol.$_SERVER['HTTP_HOST'].$listData[1]);
                    $list = json_decode($data,true);
                    $list = is_array($list) ? $list : [];
                    break;
                case 'fun': //执行指定方法
                    $fun = $listData[1];
                    $params=isset($listData[2]) ? explode(',',$listData[2]) : [];
                    $list = call_user_func_array($fun,$params);
                    break;
                case 'class': //执行指定类方法 类路径需\\隔开
                    $class = $listData[1];
                    $fun = $listData[2];
                    $params=isset($listData[3]) ? explode(',',$listData[3]) : [];
                    $list = call_user_func_array([$class,$fun],$params);
                    break;
                case 'D':
                    $class = $listData[1];
                    $path = $listData[2];
                    $fun = $listData[3];
                    $params=isset($listData[4]) ? explode(',',$listData[4]) : [];
                    $list = call_user_func_array([D($class,$path),$fun],$params);
                    break;
            }
        }else{
            $list=$listData;
        }
        return $list;
    }
    /**
     * 获取表单类型
     * @return array
     */
    public function getFormTypes() {

        $formTypes = [
            ["id"=>"text","name"=>"单行文本"],
            ["id"=>"password","name"=>"密码框"],
            ["id"=>"hidden","name"=>"隐藏框"],
            ["id"=>"switch","name"=>"switch控件"],
            ["id"=>"tags","name"=>"tags控件"],
            ["id"=>"color","name"=>"颜色选择控件"],
            ["id"=>"textarea","name"=>"多行文本"],
            ["id"=>"ckeditor","name"=>"富文本"],
            ["id"=>"select","name"=>"下拉框"],
            ["id"=>"selectpage","name"=>"selectPage控件(单选)"],
            ["id"=>"selectpages","name"=>"selectPage控件(多选)"],
            ["id"=>"laydate","name"=>"日期时间控件"],
            ["id"=>"input_array","name"=>"项目列表控件"],
            ["id"=>"checkbox","name"=>"多选框"],
            ["id"=>"radio","name"=>"单选框"],
            ["id"=>"image","name"=>"图片上传(单图)"],
            ["id"=>"file","name"=>"附件上传(单附件)"],
            ["id"=>"images","name"=>"多图上传"],
            ["id"=>"images_desc","name"=>"多图上传带描述"],
            ["id"=>"files","name"=>"多附件上传"],
        ];
        return $formTypes;
    }

    /**
     * 获取验证规则
     * @return array
     */
    public function getValidRules() {
        return [
            ['id' => 'require', 'name' => '必填'],
            ['id' => 'number', 'name' => '正整数'],
            ['id' => 'integer', 'name' => '整数'],
            ['id' => 'float', 'name' => '浮点数'],
            ['id' => 'email', 'name' => 'email'],
            ['id' => 'mobile', 'name' => '手机号'],
            ['id' => 'alphaNum', 'name' => '字母数字'],
            ['id' => 'alphaDash', 'name' => '字母数字下划线'],
            ['id' => 'chs', 'name' => '中文'],
            ['id' => 'idCard', 'name' => '身份证'],
            ['id' => 'zip', 'name' => '邮编'],
            ['id' => 'array', 'name' => '数组'],
            ['id' => 'date', 'name' => '日期'],
            ['id' => 'alpha', 'name' => '纯字母'],
            ['id' => 'activeUrl', 'name' => '域名或IP'],
            ['id' => 'ip', 'name' => 'IP']
        ];
    }

    /**
     * 格式化后端规则
     * @param $data [['field_name'=>'title','valid'=>'require','display_name'=>'标题']]
     * @return array
     */
    public function formatRules($data){
        $arr=[];
        foreach($data as $v){
            if(!empty($v['field_name']) && !empty($v['valid']) && !empty($v['display_name'])){
                $arr[$v['field_name'].'|'.$v['display_name']]=str_replace(',','|',$v['valid']);
            }
        }
        return $arr;
    }
    /**
     * 换算前端验证
     * @param $valid
     * @return string
     */
    public function transformationValid($valid, $split = ',') {
        if (empty($valid)) return '';
        $validType = [
            'require' => '*',
            'number' => 'n',
            'integer' => 'n',
            'float' => 'num',
            'email' => 'e',
            'date' => 'date',
            'alpha' => 'alpha',
            'alphaNum' => 'alphaNum',
            'alphaDash' => 'alphaDash',
            'chs' => 'zh',
            'activeUrl' => 'url',
            'mobile' => 'm',
            'idCard' => 'idcard',
            'zip' => 'p'
        ];
        $arr = explode(',', $valid);
        $result = [];
        foreach ($arr as $v) {
            if (!empty($validType[$v])) {
                $result[] = $validType[$v];
            }
        }
        $datatype = implode($split, $result);
        return $datatype;
    }
}